/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Server.domain;

import Server.domain.items.Ring;
import Server.domain.items.ChestArmor;
import Server.domain.items.Weapon;
import Server.domain.items.Equipment;
import Server.domain.items.Helmet;
import Server.domain.items.Belt;
import Server.domain.items.ItemAttribute;
import Server.domain.items.LegArmor;
import Server.domain.items.Necklace;
import Server.domain.items.Item;
import Server.domain.items.Boots;
import Server.domain.items.Gloves;
import java.awt.Color;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Sander
 */
public class Player extends Entity implements WorldOccupant
{
    private String playerName;
    private int gold;
    private long xp;
    private int level;
    private int skillPoints;
    
    private List<Item> items;
    
    private Helmet equippedHelmet;
    private ChestArmor equippedChestArmor;
    private Necklace equippedNecklace;
    private Boots equippedBoots;
    private Belt equippedBelt;
    private Gloves equippedGloves;
    private LegArmor equippedLegArmor;
    private Ring equippedLeftRing;
    private Ring equippedRightRing;
    
    private Weapon equippedLeftWeapon;
    private Weapon equippedRightWeapon;
    
    private LevelupAttributeManager levelupAttributeManager;
    
    private int manapoints;
    private int maxManapoints;
    private double manapointRegen; //mana regen per 0.25 seconds
    private double manaregenamount;
    private long lastRegenedMana;
    
    private int staminapoints;
    private int maxStaminapoints;
    private double staminapointRegen; //stamina regen per 0.25 seconds
    private double staminaregenamount;
    private long lastRegenedStamina;
    
    private double aggroMultiplier;
    
    public Player(GameLevel gl, String playerName, int lookType, Color[] colors,  int team,
            int moveSpeed, int hp, double hpregen,
            int baseArmor, int basePhysicalDamage, int baseMagicArmor, int baseMagicDamage, int mp, double mpregen,
            int sp, double spregen,
            double critChance, double critMpr, double lifestealPercentage, double spellvampPercentage, double aggroMpr, int hitboxrange)
    {
        super(gl, "player", lookType, colors, team, moveSpeed, true, hp, hpregen, 
                baseArmor, basePhysicalDamage, baseMagicArmor, baseMagicDamage, 
                critChance, critMpr, lifestealPercentage, spellvampPercentage, hitboxrange);
        
        setPlayerName(playerName);
        items = new ArrayList<Item>();
        
        setGold(0);
        setXP(0);
        setLevel(1);
        
        levelupAttributeManager = new LevelupAttributeManager();
        
        setMaxManapoints(mp);
        setManapoints(mp);
        setManapointRegen(mpregen);
        lastRegenedMana = System.currentTimeMillis();
        
        setMaxStaminapoints(sp);
        setStaminapoints(sp);
        setStaminapointRegen(spregen);
        lastRegenedStamina = System.currentTimeMillis();
        
        setAggroMultiplier(aggroMpr);
    }
    public Player(GameLevel gl, List<Item> itans, String playerName, int lookType, Color[] colors, int team,
            int gp, long exp, int lvl,
            int moveSpeed, int hp, int hpregen, 
            int baseArmor, int basePhysicalDamage, int baseMagicArmor, int baseMagicDamage,
            int mp, int mpregen, int sp, int spregen, LevelupAttributeManager lvlupattrman,
            Helmet helm, ChestArmor arm, Necklace neck, Boots boots, Belt belt, Gloves gloves,
            LegArmor leggings, Ring leftRing, Ring rightRing, Weapon leftWeap, Weapon rightWeap,
            double critChance, double critMpr, double lifestealPercentage, double spellvampPercentage, double aggroMpr,
            int hitboxrange)
    {
        super(gl, "player", lookType, colors, team, moveSpeed, true, hp, hpregen, 
                baseArmor, basePhysicalDamage, baseMagicArmor, baseMagicDamage, 
                critChance, critMpr, lifestealPercentage, spellvampPercentage, hitboxrange);
        
        setPlayerName(playerName);
        setItems(itans);
        setGold(gp);
        setXP(exp);
        setLevel(lvl);
        setLevelupAttributeManager(lvlupattrman);
        
        equip(helm);
        equip(arm);
        equip(neck);
        equip(boots);
        equip(belt);
        equip(gloves);
        equip(leggings);
        equip(leftRing);
        equip(rightRing);
        if(leftWeap != null)
        {
            equip(leftWeap);
        }
        if(rightWeap != null)
        {
            equip(rightWeap);
        }
        
        setMaxManapoints(mp);
        setManapoints(mp);
        setManapointRegen(mpregen);
        lastRegenedMana = System.currentTimeMillis();
        
        setMaxStaminapoints(sp);
        setStaminapoints(sp);
        setStaminapointRegen(spregen);
        lastRegenedStamina = System.currentTimeMillis();
        
        setAggroMultiplier(aggroMpr);
    }
      public Player(String playerName)
      {
            super(null, playerName, 1, null, 1, 200, true, 100, 0, 0, 0, 0, 0, 0, 2, 0, 0, 25);

            setPlayerName(playerName);
            setLevel(1);
            lastRegenedMana = System.currentTimeMillis();
            lastRegenedStamina = System.currentTimeMillis();
            setItems(new ArrayList<Item>());
            setLevelupAttributeManager(new LevelupAttributeManager());

            setAggroMultiplier(2);
      }
      
    public void prepareForBattle(GameLevel gl, double spawnx, double spawny)
    {
        setX(spawnx);
        setY(spawny);
        setGamelevel(gl);
        
        recalculateValues();
        
        setHitpoints(getMaxHitpoints());
        setManapoints(getMaxManapoints());
        setStaminapoints(getMaxStaminapoints());
        
        System.out.println("player "+getPlayerName()+" is prepped for battle!");
    }
    
    public String getPlayerName() { return playerName; }
    public final void setPlayerName(String playerName) { this.playerName = playerName; }
    public int getSkillPoints() { return skillPoints; }
    public int getGold() { return gold; }
    public final void setGold(int g) { this.gold = g; }
    public long getXP() { return xp; }
    public final void setXP(long exp) { this.xp = exp; }
    public int getLevel() { return level; }
    public final void setLevel(int lvl) { this.level = lvl; }
    public List<Item> getItems() { return items; }
    public final void setItems(List<Item> items) { this.items = items; }
    public long getXp() { return xp; }
    public final void setXp(long xp) { this.xp = xp; }
    public void addItem(Item i) { items.add(i); }
    public void removeItem(Item i){ items.remove(i); }
    public Belt getEquippedBelt() { return equippedBelt; }
    public Boots getEquippedBoots() { return equippedBoots; }
    public ChestArmor getEquippedChestArmor() { return equippedChestArmor; }
    public Gloves getEquippedGloves() { return equippedGloves; }
    public Helmet getEquippedHelmet() { return equippedHelmet; }
    public Ring getEquippedLeftRing() { return equippedLeftRing; }
    public Weapon getEquippedLeftWeapon() { return equippedLeftWeapon; }
    public LegArmor getEquippedLegArmor() { return equippedLegArmor; }
    public Necklace getEquippedNecklace() { return equippedNecklace; }
    public Ring getEquippedRightRing() { return equippedRightRing; }
    public Weapon getEquippedRightWeapon() { return equippedRightWeapon; }
    public LevelupAttributeManager getLevelupAttributeManager() { return levelupAttributeManager; }
    public final void setLevelupAttributeManager(LevelupAttributeManager levelupAttributeManager) 
        { this.levelupAttributeManager = levelupAttributeManager;}
    public double getManapointRegen() { return manapointRegen; }
    public final void setManapointRegen(double mpointRegen) { this.manapointRegen = mpointRegen; }
    public int getManapoints() { return manapoints; }
    public final void setManapoints(int manapoints) 
    { 
        if(manapoints > getMaxManapoints())
        {
            setManapoints(getMaxManapoints());
        }
        else
        {
            this.manapoints = manapoints;
        }
    }
    public int getMaxManapoints() { return maxManapoints; }
    public final void setMaxManapoints(int maxManapoints) { this.maxManapoints = maxManapoints; }
    public double getStamanapointRegen() { return staminapointRegen; }
    public final void setStaminapointRegen(double staminapointRegen) { this.staminapointRegen = staminapointRegen; }
    public int getStaminapoints() { return staminapoints; }
    public final void setStaminapoints(int staminapoints) 
    { 
        if(staminapoints > getMaxStaminapoints())
        {
            setStaminapoints(getMaxStaminapoints());
        }
        else
        {
            this.staminapoints = staminapoints;
        }
    }
    public int getMaxStaminapoints() { return maxStaminapoints; }
    public final void setMaxStaminapoints(int maxStaminapoints) { this.maxStaminapoints = maxStaminapoints; }
    public double getAggroMultiplier() { return aggroMultiplier; }
    public final void setAggroMultiplier(double aggroMultiplier) { this.aggroMultiplier = aggroMultiplier; }
    
    public Helmet equip(Helmet h)
    {
        Helmet x = equippedHelmet;
        equippedHelmet = h;
        recalculateValues();
        return x;
    }
    public ChestArmor equip(ChestArmor ca)
    {
        ChestArmor x = equippedChestArmor;
        equippedChestArmor = ca;
        recalculateValues();
        return x;
    }
    public Necklace equip(Necklace n)
    {
        Necklace x = equippedNecklace;
        equippedNecklace = n;
        recalculateValues();
        return x;
    }
    public Boots equip(Boots b)
    {
        Boots x = equippedBoots;
        equippedBoots = b;
        recalculateValues();
        return x;
    }
    public Belt equip(Belt b)
    {
        Belt x = equippedBelt;
        equippedBelt = b;
        recalculateValues();
        return x;
    }
    public Gloves equip(Gloves g)
    {
        Gloves x = equippedGloves;
        equippedGloves = g;
        recalculateValues();
        return x;
    }
    public LegArmor equip(LegArmor la)
    {
        LegArmor x = equippedLegArmor;
        equippedLegArmor = la;
        recalculateValues();
        return x;
    }
    public Ring equip(Ring r)
    {
        Ring x = null;
        if(equippedLeftRing == null)
        {
            x = equippedLeftRing;
            equippedLeftRing = r;
        }
        else
        {
            x = equippedRightRing;
            equippedRightRing = r;
        }
        recalculateValues();
        return x;
    }
    public Weapon[] equip(Weapon w)
    {
        Weapon[] x = null;
        if(w.isTwoHandedWeapon())
        {
            if(equippedLeftWeapon != null && equippedRightWeapon != null)
            {
                x = new Weapon[2];
                x[0] = equippedLeftWeapon;
                x[1] = equippedRightWeapon;
                equippedRightWeapon = w;
            }
            else
            {
                x = new Weapon[1];
                if(equippedLeftWeapon == null)
                {
                    x[0] = equippedRightWeapon;
                }
                else
                {
                    x[0] = equippedLeftWeapon;
                }
            }
            equippedRightWeapon = w;
        }
        else
        {
            if(equippedRightWeapon == null)
            {
                equippedRightWeapon = w;
            }
            else if(equippedLeftWeapon == null)
            {
                equippedLeftWeapon = w;
            }
            else
            {
                x = new Weapon[1];
                
                x[0] = equippedLeftWeapon;
                equippedLeftWeapon = w;
            }
        }
        recalculateValues();
        return x;
    }
    
    public void addGold(int g)
    {
        setGold(getGold() + g);
    }
    public boolean removeGold(int g)
    {
        if(g > getGold())
        {
            return false;
        }
        
        setGold(getGold() - g);
        return true;
    }
    public void addExperience(int exp)
    {
        setXP(getXP() + exp);
        if(getGamelevel() != null)
        {
            getGamelevel().getSession().tellGameSession("showtxteffect:0,200,255,"+getX()+","+getY()+","+" + "+exp+" XP!");
        }
        doLevelUpCheck();
    }
    
    public void doLevelUpCheck()
    {
        int newLevel = PlayerLevelCalculator.getLevelForExp(getXP());
        
        if(newLevel > getLevel())
        {
            int lvlIncrease = newLevel - getLevel();
            
            //TODO: use lvlIncrease to give the player points to distribute.
            skillPoints += lvlIncrease;
            setLevel(newLevel);
        }
    }
    
    @Override
    public String getNecessaryInformation()
    {
        return super.getNecessaryInformation() + ",plr_nm:"+getPlayerName();
    }

    @Override
    public String getLocationData()
    {
        return "p_nm:"+getPlayerName()+"," + super.getLocationData();
    }
    
    @Override
    public void specificUpdate() 
    {
        spregen();
        mpregen();
        //TODO
    }
    
    @Override
    public void think()
    {
        //TODO
    }
    
    @Override
    public void doSpecificAttack()
    {        
        if(getEquippedLeftWeapon() != null)
        {
            getEquippedLeftWeapon().attack(getGamelevel(), this);
        }
        if(getEquippedRightWeapon() != null)
        {
            getEquippedRightWeapon().attack(getGamelevel(), this);
        }
        
        //TODO: if player is unarmed, get the Fist weapon and use that to attack.
    }
    
    public void recalculateValues()
    {
        Equipment[] equippedItans = {
            getEquippedBelt(),
            getEquippedBoots(),
            getEquippedChestArmor(),
            getEquippedGloves(),
            getEquippedHelmet(),
            getEquippedLeftRing(),
            getEquippedRightRing(),
            getEquippedLeftWeapon(),
            getEquippedRightWeapon(),
            getEquippedLegArmor(),
            getEquippedNecklace(),
        };
        
        setArmor(0);
        setMagicArmor(0);
        setPhysicalDamage(0);
        setMagicDamage(0);
        setLifestealPercentage(0);
        setSpellvampPercentage(0);
        setWalkingSpeed(12500);
        setAttackSpeed(20);
        setHitpointRegen(0);
        setStaminapointRegen(0);
        setManapointRegen(0);
        setCriticalChance(0);
        setCriticalMultiplier(2);
        
        setAggroMultiplier(2);
        
        setMaxHitpoints(100);
        setMaxManapoints(100);
        setMaxStaminapoints(100);
        
        for(Equipment eq: equippedItans)
        {
            if(eq != null)
            {
                setArmor(getArmor()+eq.getArmorValue());
                setMagicArmor(getMagicArmor()+eq.getMagicArmorValue());

                for(ItemAttribute ia: eq.getEquipmentAttributes())
                {
                    double val = ia.getAttributeValue();
                    switch(ia.getAttribute())
                    {
                        case LIFESTEAL:
                            setLifestealPercentage(getLifestealPercentage() + val);
                            break;
                        case SPELLVAMP:
                            setSpellvampPercentage(getSpellvampPercentage() + val);
                            break;
                        case MOVEMENT:
                            setWalkingSpeed(getWalkingSpeed() + (int)val);
                            break;
                        case MAGICDAMAGE:
                            setMagicDamage(getMagicDamage() + (int)val);
                            break;
                        case ATTACKSPEED:
                            setAttackSpeed(getAttackSpeed() + (int)val);
                            break;
                        case HPREGEN:
                            setHitpointRegen(getHitpointRegen() + val);
                            break;
                        case MPREGEN:
                            setManapointRegen(getManapointRegen() + val);
                            break;
                        case SPREGEN:
                            setStaminapointRegen(getStamanapointRegen() + val);
                            break;
                        case CRITCHANCE:
                            setCriticalChance(getCriticalChance() + val);
                        break;
                        case CRITDAMAGE: 
                            setCriticalMultiplier(getCriticalMultiplier() + val);
                            break;
                        case MAXHP:
                            setMaxHitpoints(getMaxHitpoints() + (int)val);
                            break;
                        case MAXSP:
                            setMaxStaminapoints(getMaxStaminapoints() + (int)val);
                            break;
                        case MAXMP:
                            setMaxManapoints(getMaxManapoints() + (int)val);
                            break;
                    }
                }
            }
        }
        
        setPhysicalDamage(getPhysicalDamage() + (getEquippedLeftWeapon()==null?0:getEquippedLeftWeapon().getPhysicalAttackValue()));
        setPhysicalDamage(getPhysicalDamage() + (getEquippedRightWeapon()==null?0:getEquippedRightWeapon().getPhysicalAttackValue()));
        
        
        //level up attributes
        setMaxHitpoints(getMaxHitpoints() + (int)getLevelupAttributeManager().getAttributeValue(LevelupAttribute.MAX_HP));
        setMaxManapoints(getMaxManapoints() + (int)getLevelupAttributeManager().getAttributeValue(LevelupAttribute.MAX_MANA));
        setMaxStaminapoints(getMaxStaminapoints() + (int)getLevelupAttributeManager().getAttributeValue(LevelupAttribute.MAX_STAMINA));
        
        setHitpointRegen(getHitpointRegen() + getLevelupAttributeManager().getAttributeValue(LevelupAttribute.HP_REGEN));
        setManapointRegen(getManapointRegen() + getLevelupAttributeManager().getAttributeValue(LevelupAttribute.MP_REGEN));
        setStaminapointRegen(getStamanapointRegen() + getLevelupAttributeManager().getAttributeValue(LevelupAttribute.SP_REGEN));
        
        setLifestealPercentage(getLifestealPercentage() + getLevelupAttributeManager().getAttributeValue(LevelupAttribute.PRCT_LIFESTEAL));
        setSpellvampPercentage(getSpellvampPercentage() + getLevelupAttributeManager().getAttributeValue(LevelupAttribute.PRCT_SPELLVAMP));
        
        setWalkingSpeed(getWalkingSpeed() + (int)getLevelupAttributeManager().getAttributeValue(LevelupAttribute.MOVEMENT));
        
        double physicalDamagePercentage = 1;
        double magicalDamagePercentage = 1;
        double armorPercentage = 1;
        double magicalArmorPercentage = 1;
        
        double attackSpeedPercentage = 1;
        
        physicalDamagePercentage += getLevelupAttributeManager().getAttributeValue(LevelupAttribute.PRCT_PHYS_DMG) / 100;
        magicalDamagePercentage += getLevelupAttributeManager().getAttributeValue(LevelupAttribute.PRCT_MGC_DMG) / 100;
        armorPercentage += getLevelupAttributeManager().getAttributeValue(LevelupAttribute.PRCT_ARM) / 100;
        magicalArmorPercentage += getLevelupAttributeManager().getAttributeValue(LevelupAttribute.PRCT_MGC_ARM) / 100;
        
        attackSpeedPercentage += getLevelupAttributeManager().getAttributeValue(LevelupAttribute.ATK_SPD) / 100;
        
        //"max hp", "max mana", "max stamina", "hp regen", "mana regen", "stamina regen",
        //                           "% lifesteal", "% spellvamp", "% physical damage", "% magical damage", "% armor", "% magical armor",
        //                           "movement", "% attack speed"
        
        
        
        //TODO: calculate armor, physical damage, magical armor, magic power,
        //hp, stamina, mana, regens, movement, atk speed, etc etc etc!!!
        //from: itemsequipped, attributes, etc!
        
        setPhysicalDamage((int)((double)getPhysicalDamage() * physicalDamagePercentage));
        setMagicDamage((int)((double)getMagicDamage() * magicalDamagePercentage));
        setArmor((int)((double)getArmor() * armorPercentage));
        setMagicArmor((int)((double)getMagicArmor() * magicalArmorPercentage));
        
        setAttackSpeed((int)((double)getAttackSpeed() * attackSpeedPercentage));
    }
    
    public void spregen()
    {
        if(getHitpointRegen() > 0 && lastRegenedStamina + 25 <= System.currentTimeMillis())
        {
            lastRegenedStamina = System.currentTimeMillis();
            
            staminaregenamount += getHitpointRegen();
            
            int amountToRegen = (int)staminaregenamount;
            staminaregenamount -= amountToRegen;
            
            restoreStamina(amountToRegen);
        }
    }
    public void mpregen()
    {
        if(getHitpointRegen() > 0 && lastRegenedMana + 25 <= System.currentTimeMillis())
        {
            lastRegenedMana = System.currentTimeMillis();
            
            manaregenamount += getHitpointRegen();
            
            int amountToRegen = (int)manaregenamount;
            manaregenamount -= amountToRegen;
            
            restoreMana(amountToRegen);
        }
    }
    public void restoreStamina(int amount)
    {
        setStaminapoints(getStaminapoints() + amount);
    }
    public int getManapointPercentage()
    {
        return (getManapoints() * 100) / getMaxManapoints();
    }
    public void restoreMana(int amount)
    {
        setManapoints(getManapoints() + amount);
    }
    public int getStaminapointPercentage()
    {
        return (getStaminapoints() * 100) / getMaxStaminapoints();
    }
    public int getExpPercentage()
    {
        long thisLevelExp = PlayerLevelCalculator.getExperienceForLevel(getLevel());
        long nextLevelExp = PlayerLevelCalculator.getExperienceForLevel(getLevel()+1);
        
        long xpNeededToLevel = nextLevelExp - thisLevelExp;
        
        long xpGainedSoFar = getXP() - thisLevelExp;
        
        try
        {
            int prct = (int)(((double)xpGainedSoFar*((double)100)) / (double)xpNeededToLevel);
            return prct;
        }
        catch(Exception ex)
        {
            return 0;
        }
    }
    public boolean spendLevelUpAttributePoint(int index)
    {
        boolean success = getLevelupAttributeManager().spendPoint(index, getLevel());
        if(success)
        {
            recalculateValues();
        }
        return success;
    }

    public void setEquippedLeftWeapon(Weapon w) 
    {
        equippedLeftWeapon = w;
        recalculateValues();
    }
    public void setEquippedRightWeapon(Weapon w)
    {
        equippedRightWeapon = w;
        recalculateValues();
    }
    public void setEquippedLeftRing(Ring r)
    {
        equippedLeftRing = r;
        recalculateValues();
    }
    public void setEquippedRightRing(Ring r)
    {
        equippedRightRing = r;
        recalculateValues();
    }
}
